package cn.edu.dutir.corpus.cwt;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.xml.sax.InputSource;

import com.aliasi.corpus.Corpus;
import com.aliasi.corpus.Handler;
import com.aliasi.corpus.Parser;
import com.aliasi.util.Streams;
import com.ice.tar.TarEntry;
import com.ice.tar.TarInputStream;

public class TWCorpus<H extends Handler> extends Corpus<H> {

	private final Parser<H> mParser;

	public TWCorpus(Parser<H> parser) {
		mParser = parser;
	}

	/**
	 * Returns the data parser for this corpus.
	 * 
	 * @return The data parser for this corpus.
	 */
	public Parser<H> parser() {
		return mParser;
	}

	public void visitCorpus(File file) throws IOException {
		Parser<H> parser = parser();
		visit(parser, file);
	}

	public void visitCorpus(H handler, File file) throws IOException {
		Parser<H> parser = parser();
		parser.setHandler(handler);
		visit(parser, file);
	}

	private void visit(Parser<H> parser, File file) throws IOException {

		if (file.isDirectory())
			visitDir(parser, file);
		else if (file.getName().endsWith(".gz"))
			visitGzip(parser, file);
		else if (file.getName().endsWith(".zip"))
			visitZip(parser, file);
		else if (file.getName().endsWith(".tar"))
			visitTar(parser, file);
		else
			visitOrdinaryFile(parser, file);
	}

	private void visitDir(Parser<H> parser, File dir) throws IOException {

		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; ++i)
			visit(parser, files[i]);
	}

	private void visitGzip(Parser<H> parser, File gzipFile) throws IOException {

		FileInputStream fileIn = null;
		BufferedInputStream bufIn = null;
		GZIPInputStream gzipIn = null;
		try {
			fileIn = new FileInputStream(gzipFile);
			bufIn = new BufferedInputStream(bufIn);
			gzipIn = new GZIPInputStream(bufIn);
			InputSource inSource = new InputSource(gzipIn);
			parser.parse(inSource);
		} finally {
			Streams.closeInputStream(gzipIn);
			Streams.closeInputStream(bufIn);
			Streams.closeInputStream(fileIn);
		}
	}

	private void visitZip(Parser<H> parser, File zipFile) throws IOException {

		FileInputStream fileIn = null;
		BufferedInputStream bufIn = null;
		ZipInputStream zipIn = null;
		try {
			fileIn = new FileInputStream(zipFile);
			bufIn = new BufferedInputStream(bufIn);
			zipIn = new ZipInputStream(bufIn);
			ZipEntry entry = null;
			while ((entry = zipIn.getNextEntry()) != null) {
				if (entry.isDirectory())
					continue;
				InputSource inSource = new InputSource(zipIn);
				parser.parse(inSource);
			}
		} finally {
			Streams.closeInputStream(zipIn);
			Streams.closeInputStream(bufIn);
			Streams.closeInputStream(fileIn);
		}
	}

	private void visitTar(Parser<H> parser, File tarFile) throws IOException {

		FileInputStream fileIn = null;
		BufferedInputStream bufIn = null;
		TarInputStream tarIn = null;
		try {
			fileIn = new FileInputStream(tarFile);
			bufIn = new BufferedInputStream(bufIn);
			tarIn = new TarInputStream(bufIn);
			TarEntry entry = null;
			while ((entry = tarIn.getNextEntry()) != null) {
				if (entry.isDirectory())
					continue;
				InputSource inSource = new InputSource(tarIn);
				parser.parse(inSource);
			}
		} finally {
			Streams.closeInputStream(tarIn);
			Streams.closeInputStream(bufIn);
			Streams.closeInputStream(fileIn);
		}
	}

	private void visitOrdinaryFile(Parser<H> parser, File file)
			throws IOException {

		BufferedReader reader = new BufferedReader(new FileReader(file));
		InputSource in = new InputSource(reader);
		in.setSystemId(file.getCanonicalPath());
		parser.parse(in);
		reader.close();
	}
}
